package org.gm.mybatis.ext.service;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.gm.mybatis.ext.mapper.BaseMapper;
import org.gm.mybatis.ext.sql.SqlQuery;
import org.gm.mybatis.ext.util.StringHelper;

public abstract class BaseServiceImpl<T, E> implements BaseService<T, E> {
	/**
	 * 获取当前数据库操作对象
	 * @return
	 */
	protected abstract BaseMapper<T, E> getDAO();

	public int countByExample(E example) {
		// TODO Auto-generated method stub
		return getDAO().countByExample(example);
	}

	public int countBySqlQuery(SqlQuery sqlQuery) {
		// TODO Auto-generated method stub
		return getDAO().countBySqlQuery(sqlQuery);
	}

	public int deleteByExample(E example) {
		// TODO Auto-generated method stub
		return getDAO().deleteByExample(example);
	}

	public int deleteByPrimaryKey(Serializable id) {
		// TODO Auto-generated method stub
		return getDAO().deleteByPrimaryKey(id);
	}

	public int insert(T record) {
		// TODO Auto-generated method stub
		return getDAO().insert(record);
	}

	public int insertSelective(T record) {
		// TODO Auto-generated method stub
		return getDAO().insertSelective(record);
	}

	public List<T> selectByExample(E example) {
		// TODO Auto-generated method stub
		return getDAO().selectByExample(example);
	}

	public List<T> selectRelationByExample(E example) {
		// TODO Auto-generated method stub
		return getDAO().selectRelationByExample(example);
	}

	public T selectByPrimaryKey(Serializable id) {
		// TODO Auto-generated method stub
		return getDAO().selectByPrimaryKey(id);
	}

	public T selectRelationByPrimaryKey(Serializable id) {
		// TODO Auto-generated method stub
		return getDAO().selectRelationByPrimaryKey(id);
	}

	public List<Map<String, Object>> selectBySqlQuery(SqlQuery sqlQuery) {
		// TODO Auto-generated method stub
		List<Map<String, Object>> list = getDAO().selectBySqlQuery(sqlQuery);
		List<Map<String, Object>> out = new LinkedList<Map<String, Object>>();
		for (Map<String, Object> item : list) {
			if (item == null) {
				continue;
			}
			Set<String> keySet = item.keySet();
			Iterator<String> iterator = keySet.iterator();
			Map<String, Object> outm = new HashMap<String, Object>();
			while (iterator.hasNext()) {
				String key = iterator.next();
				Object val = item.get(key);
				String objKey = StringHelper.dbNameToJavaName(key);
				if (val == null) {
					outm.put(objKey, null);
				} else {
					if (val instanceof Timestamp) {
						Timestamp time = (Timestamp) val;
						outm.put(objKey, StringHelper.formatDate(new java.util.Date(time.getTime()), 0));
					} else if (val instanceof java.sql.Date) {
						java.sql.Date date = (java.sql.Date) val;
						outm.put(objKey, StringHelper.formatDate(new java.util.Date(date.getTime()), 4));
					} else {
						outm.put(objKey, val);
					}
				}
			}
			out.add(outm);
		}
		return out;
	}

	public int updateByExampleSelective(T record, E example) {
		// TODO Auto-generated method stub
		return getDAO().updateByExampleSelective(record, example);
	}

	public int updateByExample(T record, E example) {
		// TODO Auto-generated method stub
		return getDAO().updateByExample(record, example);
	}

	public int updateByPrimaryKeySelective(T record) {
		// TODO Auto-generated method stub
		return getDAO().updateByPrimaryKeySelective(record);
	}

	public int updateByPrimaryKey(T record) {
		// TODO Auto-generated method stub
		return getDAO().updateByPrimaryKey(record);
	}

	public int updatebySqlQuery(SqlQuery sqlQuery) {
		// TODO Auto-generated method stub
		return getDAO().updatebySqlQuery(sqlQuery);
	}
	
	public int updateFromMapByExample(Map<String, ?> record, E example) {
		// TODO Auto-generated method stub
		return getDAO().updateFromMapByExample(record, example);
	}
	
	/**
	 * 设置分页页码等属性
	 * @param example
	 * @param page
	 * @param pageSize
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	protected E loIntoExample(E example, int page, int pageSize) throws Exception {
		if(null == example){
			example = (E)StringHelper.getSuperClassGenricType(getClass(), 1).newInstance();
		}
		Method method = example.getClass().getDeclaredMethod("getOrderByClause");
		String order = (String) method.invoke(example);
		if(StringHelper.isEmpty(order)){
			throw new RuntimeException("排序字段未设置！");
		};
		// 设置分页限制
		int offset = (page - 1) * pageSize;
		StringBuffer sb = new StringBuffer(order).append(" limit ").append(pageSize).append(" offset ").append(offset);

		method = example.getClass().getDeclaredMethod("setOrderByClause", String.class);
		method.invoke(example, sb.toString());
		return example;
	}

	public PageResult<T> pageByExample(E example, int page, int pageSize) throws Exception {
		// TODO Auto-generated method stub
		PageResult<T> pageResult =  new PageResult<T>();
		pageResult.setTotal(countByExample(example));
		pageResult.setRows(selectByExample(loIntoExample(example, page, pageSize)));
		pageResult.setPage(page);
		pageResult.setPageTotal((pageResult.getTotal()%pageSize==0)?(pageResult.getTotal()/pageSize):(pageResult.getTotal()/pageSize+1));
		return pageResult;
	}

	public PageResult<T> pageRelationByExample(E example, int page, int pageSize) throws Exception {
		// TODO Auto-generated method stub
		PageResult<T> pageResult =  new PageResult<T>();
		pageResult.setTotal(countByExample(example));
		pageResult.setRows(selectRelationByExample(loIntoExample(example, page, pageSize)));
		pageResult.setPage(page);
		pageResult.setPageTotal((pageResult.getTotal()%pageSize==0)?(pageResult.getTotal()/pageSize):(pageResult.getTotal()/pageSize+1));
		return pageResult;
	}

	public PageResult<Map<String, Object>> pageSqlQuery(SqlQuery sqlQuery, int page, int pageSize) throws Exception {
		// TODO Auto-generated method stub
		PageResult<Map<String, Object>> pageResult =  new PageResult<Map<String, Object>>();
		pageResult.setTotal(countBySqlQuery(sqlQuery));
		
		int offset = (page - 1) * pageSize;
		StringBuffer newsql = new StringBuffer(sqlQuery.getOrderString());
		newsql.append(" limit ").append(pageSize).append(" offset ").append(offset);
		sqlQuery.setOrderString(newsql.toString());
		sqlQuery.setExistOrder(true);
		pageResult.setRows(selectBySqlQuery(sqlQuery));
		pageResult.setPage(page);
		pageResult.setPageTotal((pageResult.getTotal()%pageSize==0)?(pageResult.getTotal()/pageSize):(pageResult.getTotal()/pageSize+1));
		return pageResult;
	}

}